/**
 * 
 */
package edu.cmu.lti.lm.dt;

import java.io.PrintWriter;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * The feature selection
 * @author Qin Gao
 *
 */
public abstract class Feature implements Serializable{
	private Set<String> pos = new HashSet<String>();


	public abstract String getName();
	
	/**
	 * The feature value given h 
	 * @param h
	 * @return
	 */
	public abstract String getValue(History h);
	


	
	public Set<String> getPossibleValues() {
		return pos;
	}


	public Pair<Question,Double>
		getBestQuestion(EntryCollection c, PrintWriter wr,double base){
		Question q = new Question();
		q.setFeature(this);
		boolean rec ;
		double bestScore =  1e99;
		String bestKey = null;
		int i = 0;
		do{
			System.err.println("BEST SCORE BEFORE ROUND " + i +" : " + bestScore);
			i++;
			rec = false;
			bestKey = null;
			Iterator<String> it = getPossibleValues().iterator();
			while(it.hasNext()){
				String key = it.next();
				if(!q.contains(key)){
					q.add(key);
					Pair<Double, Pair<EntryCollection, EntryCollection>> v 
					= c.getConditionalEntropy(q);
					Iterator<String> s = q.iterator();
					while(s.hasNext()){
						wr.print(s.next());
						wr.print(" ");
					}
					wr.print(v.getFirst());
					wr.print(" #");
					wr.println(base - v.getFirst());
					wr.flush();
					if(v.getFirst()<bestScore){
						bestScore = v.getFirst();
						bestKey = key;
						System.err.println("Find better key : " + key + " | " +bestScore);
					}
					q.remove(key);
				}
			}
			if(bestKey!=null){
				System.err.println("Add the key to keyset : " + bestKey + " | " +bestScore);
				q.add(bestKey);
				rec = true;
				Iterator<String> it1 = q.iterator();
				System.err.println("Current keyset:");
				while(it1.hasNext()){
					System.err.print(it1.next());
					System.err.print(" ");
				}
				System.err.println();
			}
			bestKey = null;
			List<String> keys = new LinkedList<String>();
			keys.addAll(q.set());
			it = keys.iterator();
			while(it.hasNext()){
				String key = it.next();
				q.remove(key);
				Pair<Double, Pair<EntryCollection, EntryCollection>> v 
				= c.getConditionalEntropy(q);
				if(v.getFirst()<bestScore){
					bestScore = v.getFirst();
					bestKey = key;
					System.err.println("Find better key to remove : " + key + " | " +bestScore);
				}
				q.add(key);
			}
			if(bestKey != null){
				System.err.println("Remove the key from keyset : " + bestKey +" | " + bestScore);
				q.remove(bestKey);
				rec = true;
				Iterator<String> it1 = q.iterator();
				System.err.println("Current keyset:");
				while(it1.hasNext()){
					System.err.print(it1.next());
					System.err.print(" ");
				}
				System.err.println();
			}
			if(rec){
				System.err.println("Some chages made, so continue round " + i + " Best Score: " + bestScore);
			}else{
				System.err.println("No chages made, so Finished  " + i + " Best Score: " + bestScore);
				System.err.println("----------------------------------------------------------------");
			}
		}while(rec);
		return new Pair<Question,Double>(q,bestScore);
		
	}


	public void addValue(History h) {
		pos.add(getValue(h));
	}
}
